﻿using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.ServiceProcess;
using System.Collections.Generic;
using IMDBApi.App.Properties;
using IMDBApi.Contracts.Entities.Title.MainDetail;
using IMDBApi.Implementation;
using IMDBApi.Implementation.Models;
using IMDBApi.Contracts;
using IMDBApi.Contracts.Entities;

namespace IMDBApi.App.Views
{
    public partial class MainView : CustomUserControl
    {
        /// <summary>
        /// ...
        /// </summary>
        private ServiceController controller = new ServiceController();

        /// <summary>
        /// ...
        /// </summary>
        private List<MovieFile> movieList = new List<MovieFile>();

        /// <summary>
        /// ...
        /// </summary>
        public MainView(Form parent)
        {
            InitializeComponent();

            this.Parent = parent;
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_Load(object sender, EventArgs e)
        {
            AppendLog("Loading Files...", Color.Gray);
            AppendLog("Loading JSON Files...", Color.Gray);
            this.movieList = PollingUtils.LoadFiles();

            AppendLog("Prepare UI...", Color.Gray);
            FillDataGridView();

            AppendLog("Connecting to Service...", Color.Gray);
            ConnectToService();
        }

        /// <summary>
        /// ...
        /// </summary>
        private void ConnectToService()
        {
            try
            {
                this.controller = new ServiceController("IMDBApi", Environment.MachineName);
                AppendLog("Service found.", Color.Orange);

                if( this.controller.Status == ServiceControllerStatus.Running )
                    AppendLog("Service running.", Color.Green);
                else if (this.controller.Status == ServiceControllerStatus.Stopped)
                    AppendLog("Service stopped.", Color.Red);
            }
            catch (Exception ex)
            {
                AppendLog("Service not found.\n" + ex.Message, Color.Orange);
            }
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                controller.Start();
                AppendLog("Service started...", Color.Green);
            }
            catch (Exception ex)
            {
                AppendLog(ex.Message, Color.Red);
            }
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                controller.Stop();
                AppendLog("Service stopped...", Color.Red);
            }
            catch (Exception ex)
            {
                AppendLog(ex.Message, Color.Red);
            }
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            try
            {
                controller.Refresh();

                if( controller.Status == ServiceControllerStatus.Running )
                    (this.Parent as MainForm).SetStatus("Service running.", Resources.traffic_lights_green);
                else if( controller.Status == ServiceControllerStatus.Stopped )
                    (this.Parent as MainForm).SetStatus("Service stopped.", Resources.traffic_lights_red);
                else
                    (this.Parent as MainForm).SetStatus("Service pending.", Resources.traffic_lights_yellow);
            }
            catch (Exception ex)
            {
                AppendLog(ex.Message, Color.Red);
            }
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void QueryDetailsMenuItem_Click(object sender, EventArgs e)
        {
            (this.Parent as MainForm).ChangeUserControl(new DetailView(this.Parent) { movieFile = (this.dgvFiles.CurrentRow.DataBoundItem as MovieFile) });
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DownloadDetailsMenuItem_Click(object sender, EventArgs e)
        {
            (this.Parent as MainForm).SetLoader(true);

            (this.dgvFiles.CurrentRow.DataBoundItem as MovieFile).ChangeState(DownloadState.Downloading);

            new GenericBackgroundWorker().RunAsync<BackgroundWorker, MovieFile, MovieFile>(DownloadDetailsDoWork, (this.dgvFiles.CurrentRow.DataBoundItem as MovieFile), DownloadDetailsWorkerCompleted, DownloadDetailsWorkerCompletedWithError);
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGridView_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                foreach (DataGridViewRow row in this.dgvFiles.Rows)
                    row.Selected = false;

                System.Windows.Forms.DataGridView.HitTestInfo info = this.dgvFiles.HitTest(e.X, e.Y);
                if (info.ColumnIndex >= 0 && info.RowIndex >= 0)
                {
                    DataGridViewCell cell = this.dgvFiles[info.ColumnIndex, info.RowIndex];
                    cell.Selected = true;

                    this.DetailsMenuItem.Enabled = ((cell.OwningRow.DataBoundItem as MovieFile).State == DownloadState.Local);
                    this.DownloadDetailsMenuItem.Enabled = ((cell.OwningRow.DataBoundItem as MovieFile).State == DownloadState.Missing);

                    this.contextMenuStrip.Show(Cursor.Position);
                }
            }
        }

        /// <summary>
        /// ...
        /// </summary>
        private void FillDataGridView()
        {
            this.dgvFiles.DataSource = this.movieList;
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="message"></param>
        /// <param name="color"></param>
        private void AppendLog(string message, Color color)
        {
            var oldLength = this.rtbLog.Text.Length;

            this.rtbLog.AppendText(message + Environment.NewLine);
            this.rtbLog.Select(oldLength, message.Length);
            this.rtbLog.SelectionColor = color;
        }

        #region BackgroundWorker Download

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="outputArgument"></param>
        private void DownloadDetailsWorkerCompleted(MovieFile outputArgument)
        {
            (this.Parent as MainForm).SetLoader(false);

            (this.dgvFiles.CurrentRow.DataBoundItem as MovieFile).ChangeState(DownloadState.Local);

            (this.dgvFiles.CurrentRow.DataBoundItem as MovieFile).JSONFullname = outputArgument.JSONFullname;
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="ex"></param>
        private void DownloadDetailsWorkerCompletedWithError(Exception ex)
        {
            (this.Parent as MainForm).SetStatus(ex.Message);
        }

        /// <summary>
        /// ...
        /// </summary>
        /// <param name="worker"></param>
        /// <param name="inputArgument"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private MovieFile DownloadDetailsDoWork(BackgroundWorker worker, MovieFile inputArgument, DoWorkEventArgs e)
        {
            if (this.dgvFiles.CurrentRow.DataBoundItem == null)
                return null;

            string json = string.Empty;
            string fileName = inputArgument.Filename;
            string fileDirectory = inputArgument.Path;

            json = new Query().FindMovieJson(fileName);
            MainDetail mainDetail = JSONSerializer.Deserialize<MainDetail>(json);

            if (json != string.Empty)
            {
                inputArgument.JSONFullname = Path.Combine(fileDirectory, "Rating" + mainDetail.Data.Rating + "#" + fileName);
                File.WriteAllText(inputArgument.JSONFullname, json);
            }

            return inputArgument;
        }

        #endregion
    }
}
